package code;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class Grafo implements Serializable {

    private String nome;
    private Map<String, No> listaNo = new LinkedHashMap<String, No>();

    public Grafo(String nome) throws Exception {
        this.setNome(nome);
    }

    public Map getListaNo() {
        return listaNo;
    }

    public void setNome(String nome) throws Exception {
        if (nome == null || nome.isEmpty()) {
            throw new Exception("Nome do gráfo inválido");
        }
        this.nome = nome;
    }

    public String getNome() {
        return this.nome;
    }

    public No getNo(String nome) throws Exception {
        No no = listaNo.get(nome);
        if (no == null) {
            throw new Exception("Nó não encontrado: " + nome);
        }
        return no;
    }

    public boolean existeNo(String nome) {
        if (listaNo.get(nome) == null) {
            return false;
        } else {
            return true;
        }
    }

    public void addNo(No no) throws Exception {
        No noTeste;
        noTeste = listaNo.put(no.getNome(), no);

        if (noTeste != null) {
            throw new Exception("O nó informado já existe: " + no.getNome());
        }
    }

    public No removeNo(String nome) throws Exception {
        No noTeste = listaNo.remove(nome);
        if (noTeste == null) {
            throw new Exception("Nó não existe, nome: " + nome);
        }
        return noTeste;
    }

    public Aresta getAresta(String nome) {
        Collection<No> nos = listaNo.values();
        Aresta aresta = null;
        for (No no : nos) {
            aresta = no.getAresta(nome);
            if (aresta != null) {
                return aresta;
            }
        }
        return null;
    }

    public float getCustoTotal() {
        float custoTotal = 0;
        Collection<No> nos = this.getListaNo().values();
        Map<String, Aresta> mapAresta = new HashMap<String, Aresta>();
        for (No no: nos) {
            custoTotal += no.getCusto();
            Collection<Aresta> arestas = no.getListaArestas().values();
            for (Aresta aresta : arestas) {
                mapAresta.put(aresta.getNome(), aresta);
            }
        }
        Collection<Aresta> arestas = mapAresta.values();
        for (Aresta aresta: arestas) {
            custoTotal += aresta.getCusto();
        }
        return custoTotal;
    }

    @Override
    public String toString() {
        return this.nome;
    }

    public String getResultado() {
        StringBuilder sb = new StringBuilder();
        sb.append("Grafo "+this.getNome() + "\n");

        Map<String, Aresta> mapAresta = new HashMap<String, Aresta>();
        Collection<No> nos = this.getListaNo().values();        
        for (No no: nos) {
            sb.append(no.getResultado() + "\n");
            Collection<Aresta> arestas = no.getListaArestas().values();
            for (Aresta aresta: arestas) {
                mapAresta.put(aresta.getNome(), aresta);
            }
        }

        Collection<Aresta> arestas = mapAresta.values();        
        for (Aresta aresta : arestas) {
            sb.append(aresta.getResultado() + "\n");
        }
        sb.append("Custo total do grafo " + this.nome + ": " + this.getCustoTotal());
        return new String(sb);
    }
}
